#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : error_codes.py
@TIME          : 2025/03/09 17:38:08
@AUTHOR        : chenlip
@VERSION       : 0.0.1
@DESCRIPTION   : 错误码标准系统

错误码标准系统，使用方法：
1. 引用本文件: from app.common.error_codes import ErrorCode
2. 使用常量获取错误码: ErrorCode.USER_NOT_EXIST
3. 使用方法获取错误信息: ErrorCode.get_message(ErrorCode.USER_NOT_EXIST)
4. 创建标准错误响应: ErrorCode.error_response(ErrorCode.USER_NOT_EXIST)
'''
# --------------------------引用--------------------------
import os, sys, json
from typing import Dict, Any, Optional
from app.conf.config import Config as conf
from app.common.logutil import log_error
# --------------------------引用--------------------------

class ErrorCode:
    """
    错误码管理类 - 从JSON配置文件加载错误码定义
    
    提供以下功能:
    1. 使用类似常量的方式访问错误码
    2. 获取错误码对应的错误消息
    3. 生成标准的错误响应和成功响应
    
    Example:
        >>> from app.common.error_codes import ErrorCode
        >>> # 获取错误码
        >>> code = ErrorCode.USER_NOT_EXIST
        >>> # 获取错误消息
        >>> message = ErrorCode.get_message(code)
        >>> # 创建错误响应
        >>> response = ErrorCode.error_response(code)
    """
    
    # 成功码
    SUCCESS = "10000"
    
    # 未知错误码
    UNKNOWN_ERROR = "99999"
    
    # 错误码文件路径
    _ERROR_CODE_FILE = os.path.join(conf.APPLICATION_ROOT, 'app', 'conf', 'error_code.json')
    
    # 错误码映射 - 业务友好名称到错误码的映射
    _CODE_MAP = {}
    
    # 错误码配置 - 从JSON文件加载的完整配置
    _error_codes = None
    
    @classmethod
    def _init_code_map(cls):
        """初始化错误码映射"""
        # 加载错误码配置
        error_codes = cls._load_error_codes()
        
        # 系统错误码映射
        for code, message in error_codes.get('system', {}).items():
            # 提取消息的第一个词作为错误名称
            name_parts = message.upper().split()
            if len(name_parts) > 1:
                name = f"SYS_{name_parts[0]}_{name_parts[1]}"
            else:
                name = f"SYS_{name_parts[0]}"
            
            # 替换特殊字符
            name = name.replace('，', '_').replace(',', '_').replace('、', '_')
            name = name.replace('：', '_').replace(':', '_')
            name = name.replace('(', '').replace(')', '')
            
            # 添加映射
            cls._CODE_MAP[name] = code
        
        # 业务错误码映射
        for code, message in error_codes.get('bussiness', {}).items():
            # 对消息进行处理，提取关键词作为错误名称
            if "用户名已存在" in message:
                name = "USER_ALREADY_EXISTS"
            elif "邮箱已注册" in message:
                name = "EMAIL_ALREADY_EXISTS"
            elif "手机号已注册" in message:
                name = "PHONE_ALREADY_EXISTS"
            elif "密码错误" in message:
                name = "PASSWORD_INCORRECT"
            elif "用户不存在" in message:
                name = "USER_NOT_EXIST"
            elif "用户未登录" in message:
                name = "USER_NOT_LOGIN"
            elif "用户未激活" in message:
                name = "USER_NOT_ACTIVE"
            elif "用户已禁用" in message:
                name = "USER_DISABLED"
            elif "用户名和密码不能为空" in message:
                name = "LOGIN_EMPTY"
            elif "获取用户元数据失败" in message:
                name = "USER_META_ERROR"
            elif "手机号和密码不能为空" in message:
                name = "PHONE_LOGIN_EMPTY"
            elif "登录失败" in message:
                name = "LOGIN_FAILED"
            elif "用户注册失败" in message:
                name = "REGISTER_FAILED"
            elif "未知错误" in message:
                name = "UNKNOWN_USER_ERROR"
            else:
                # 默认处理：取消息的前两个词作为错误名称
                name_parts = message.upper().split()
                if len(name_parts) > 1:
                    name = f"{name_parts[0]}_{name_parts[1]}"
                else:
                    name = name_parts[0]
            
            # 添加映射
            cls._CODE_MAP[name] = code
    
    @classmethod
    def _load_error_codes(cls) -> Dict:
        """
        从JSON文件加载错误码配置
        
        Returns:
            Dict: 错误码配置字典
        """
        if cls._error_codes is None:
            try:
                with open(cls._ERROR_CODE_FILE, 'r', encoding='utf-8') as f:
                    cls._error_codes = json.load(f)
            except Exception as e:
                
                log_error(f"加载错误码配置文件失败", e)
                
                # 提供默认错误码映射
                cls._error_codes = {
                    "system": {"59999": "系统错误"},
                    "bussiness": {"69999": "业务错误"}
                }
            
            # 初始化错误码映射
            cls._init_code_map()
            
        return cls._error_codes
    
    @classmethod
    def __getattr__(cls, name):
        """
        通过属性访问获取错误码
        
        Args:
            name: 错误码名称
            
        Returns:
            str: 错误码
            
        Raises:
            AttributeError: 如果错误码不存在
        """
        # 确保错误码已加载
        cls._load_error_codes()
        
        # 检查是否存在该错误码
        if name in cls._CODE_MAP:
            return cls._CODE_MAP[name]
        
        # 抛出属性错误
        raise AttributeError(f"'{cls.__name__}' has no attribute '{name}'")
    
    @classmethod
    def get_message(cls, code: str) -> str:
        """
        获取错误码对应的消息
        
        Args:
            code (str): 错误码
            
        Returns:
            str: 错误消息
        """
        error_codes = cls._load_error_codes()
        
        # 确定错误类型
        if code.startswith("5"):
            error_type = "system"
        elif code.startswith("6"):
            error_type = "bussiness"
        else:
            return f"未知错误[{code}]"
        
        # 获取错误消息
        return error_codes.get(error_type, {}).get(code, f"未知错误[{code}]")
    
    @classmethod
    def error_response(cls, code: str, message: Optional[str] = None, data: Any = None) -> Dict:
        """
        创建标准错误响应
        
        Args:
            code (str): 错误码
            message (str, optional): 自定义错误消息. 默认为None, 使用错误码对应的消息
            data (Any, optional): 错误相关数据. 默认为None
            
        Returns:
            Dict: 标准错误响应
        """
        _message = cls.get_message(code)
        if message:
            _message += f" [{code}]: {message}" 
            
        return {
            "success": False,
            "code": code,
            "message": _message,
            "data": data
        }
    
    @classmethod
    def success_response(cls, data: Any = None, message: str = "操作成功") -> Dict:
        """
        创建标准成功响应
        
        Args:
            data (Any, optional): 响应数据. 默认为None
            message (str, optional): 成功消息. 默认为"操作成功"
            
        Returns:
            Dict: 标准成功响应
        """
        return {
            "success": True,
            "code": cls.SUCCESS,
            "message": message,
            "data": data
        }